// 十、高级类型（上）

// 1.交叉类型 &

// 取多个类型的并集，使用&定义。
const mergeFunc = <T, U>(arg1: T, arg2: U): T & U => {
  let res = <T & U>{}
  res = Object.assign(arg1, arg2)
  return res
}
mergeFunc({ a: 'a' }, { b: 'b' })

// 2.联合类型 |

const getLengthFunc = (content: string | number): number => {
  if (typeof content === 'string') return content.length
  else {
    return content.toString().length
  }
}
// console.log(getLengthFunc(1234));

// 3.类型保护

const valueList = [123, 'abc']
const getRandomValue = () => {
  const number = Math.random() * 10
  if (number < 5) { return valueList[0] }
  else { return valueList[1] }
}
const res1 = getRandomValue()
// console.log(res1);

// 3.1 is
// function isString(value: number | string): value is string {
//   return typeof value === 'string'
// }

// if (isString(res1)) {
//   console.log(res1.length);
// } else {
//   console.log(res1.toFixed());
// }

// 3.2 typeof 只能做===  或者!==  后面比较的类型只能是string/number/boolean/symbol中的一种
// if (typeof res1 === 'string') {
//   console.log(res1.length);
// } else {
//   console.log(res1.toFixed());
// }

// 3.3 instanceof 
class CreatedByClass1 {
  public age = 18
  constructor() { }
}
class CreatedByClass2 {
  public name = 'lp'
  constructor() { }
}
function getRandomItem() {
  return Math.random() < 0.5 ? new CreatedByClass1() : new CreatedByClass2()
}
const item1 = getRandomItem()
// if (item1 instanceof CreatedByClass1) {
//   console.log(item1.age);
// } else {
//   console.log(item1.name);

// }

// 4.null和undefined

let values = '123'
values = undefined

const sumFunc = (x: number, y?: number) => {
  return x + (y || 0)
}

// 5.类型保护和类型断言

const getLengthFunction = (value: string | null): number => {
  // if (value === null) { return 0 }
  // else { return value.length }
  return (value || '').length
}

// 在不为null的值后边加类型断言!
function getSpliceStr(num: number | null): string {
  function getRes(prefix: string) {
    return prefix + num!.toFixed().toString()
  }
  num = num || 0.1
  return getRes('lp-')
}
// console.log(getSpliceStr(1.2));
// 6.类型别名 type

type TypeString = string
let str2: TypeString

type PositionType<T> = { x: T, y: T }
const position1: PositionType<number> = {
  x: 1,
  y: -1
}
const position2: PositionType<string> = {
  x: 'left',
  y: 'right'
}
// type Childs<T> = {
//   current: T,
//   child?: Childs<T>
// }
// let ccc: Childs<string> = {
//   current: 'first',
//   child: {
//     current: 'second',
//     child: {
//       current: 'third',
//     }
//   }
// }
// type Childs = Childs[] //只能在属性中使用，不能直接使用

type Alias = {
  num: number
}
interface Interface {
  num: number
}
let _alias: Alias = {
  num: 123
}
let _interface: Interface = {
  num: 123
}
_alias = _interface

// 7.字面量类型

// 7.1字符串字面量

type Name = 'lp'
// const name3:Name = 'hha'
type Direction = 'north' | 'east' | 'south' | 'west'
function getDirectionFirstLetter(direction: Direction) {
  return direction.substr(0, 1)
}
// console.log(getDirectionFirstLetter('west'));

// 7.2数字字面量

type Age = 18

interface InfoInterfaces {
  name: string
  age: Age
}
const _info: InfoInterfaces = {
  name: 'lp',
  age: 18
}

// 8.枚举成员类型

// enum

// 9.可辨识联合

// 可辨识联合两个条件：
// 1.具有普通的单例类型属性
// 2.一个类型别名包含了哪些类型的联合
interface Square {
  kind: 'square'
  size: number
}
interface Rectangle {
  kind: 'rectangle'
  height: number
  width: number
}
interface Circle {
  kind: 'circle'
  radius: number
}
type Shape = Square | Rectangle | Circle

function assertNever(value:never):never {
  throw new Error('unexpected object:'+value)
}
function getArea(s: Shape):number {
  switch (s.kind) {
    case 'square':
      return s.size * s.size;
      break;
    case 'rectangle':
      return s.height * s.width
      break;
    case 'circle':
      return Math.PI * s.radius ** 2
      break;
    default:
      assertNever(s)
      break;
  }
}
